/**
 * fileinput.js v1.0
 * Author: zengyl
 * License: MIT
 */

(jQuery && (function($) {
	//主要函数
	var fileinput = function(cbfn, conf) {
		//重复！
		if(this.attr("fileinput")) return false;

		//读取文件时执行的函数
		cbfn = cbfn || function(fl,fn){fn.ok();};

		//返回值
		var ret = {
			elements: {},	//所有元素
			state: "",		//状态
			file: null,		//当前处理的文件
			trueFile: null	//处理完毕(执行过ok())的文件
		};

		//默认设定
		conf = $.extend(true, {
			accept: "", //支持的文件类型，用","连接的字符串，或数组。如".foo,.bar"或[".foo",".bar"]
			size: "", //尺寸，lg、sm或不填
			class: {//代替默认设置的class
				browser_btn: "btn btn-primary",
			},
			lang: { //本地化
				nameCapt: "拖动文件或点击按钮以上传文件",
				browser: "浏览文件",
				processing: "处理中：",
				error: ["错误。", "错误："], //无信息和有信息
				done: "完成：",
				drag: "松开以上传文件",
				nonfile: "不是文件！",
				refuseType: "不支持该文件类型！",
			},
			drag: true //可拖动上传文件
		}, conf);

		//允许的文件类型
		var acceptList = Array.isArray(conf.accept) ? conf.accept : conf.accept.split(",");
		acceptList = acceptList.filter(function(e) {
            return (e.lastIndexOf(".") == 0) && (e.length > 1);
        });
		for(let i in acceptList)
			acceptList[i] = acceptList[i].toLowerCase()



		//所有元素
		var el = ret.elements = {};

		//输入框组包裹
		el.wrapper = $("<div class=\"input-group\"></div>")
			.addClass(conf.size ? "input-group-" + conf.size : ""); //尺寸
		//文件名显示
		el.nameCapt = $("<input readonly=\"\">").addClass("fileinput-nameCapt form-control");
		//浏览文件按钮
		el.browser_btn = $("<div class=\"fileinput-browser-btn btn\"></div>")
			.addClass(conf.class.browser_btn);
		//主要的input控件
		el.fileinput = $("<input type=\"file\">").attr("accept", acceptList.join(","));
		//组装
		el.browser_btn.text(conf.lang.browser)
			.on("click", function(e){e.stopPropagation();el.fileinput.click();});
		el.wrapper.append(el.nameCapt).append(el.fileinput)
			.append($("<div class=\"input-group-btn\"></div>").append(el.browser_btn));



		//文件是否正在拖动
		var fileDrag = false; 

		//更改状态，输入状态和提示消息
		var changeState = function(s, t, r=true) {
			if(r) ret.state = s;
			el.nameCapt.attr("value", t).attr("state", s);
		};

		//自动更新状态，或弹出提示并在一顿时间后隐藏。输入状态、消息
		var tmpMsg = {s:"", t:"", tm: 0};
		var setMsg = function(s, t) {
			var tm = new Date().getTime();
			if(s) {
				tmpMsg.s = s;
				tmpMsg.t = t;
				tmpMsg.tm = tm;
				fileDrag || changeState(s, t);
				setTimeout(function() {
					if(tmpMsg.s == s && tmpMsg.t == t && tmpMsg.tm == tm) {
						setMsg();
						tmpMsg = {s:"", t:"", tm: 0};
					}
				}, 2000);
			}else if(!fileDrag) {
				if(tm < (tmpMsg.tm + 2000)) {
					let s = tmpMsg.s;
					let t = tmpMsg.t;
					let tm2 = tmpMsg.tm;
					changeState(tmpMsg.s, tmpMsg.t);
					setTimeout(function() {
						if(tmpMsg.s == s && tmpMsg.t == t && tmpMsg.tm == tm2) {
							setMsg();
							tmpMsg = {s:"", t:"", tm: 0};
						}
					}, 2000 - tm + tmpMsg.tm);
				}else if(!ret.file) {
					if (ret.trueFile)
						changeState("ok", ret.trueFile.name);
					else
						changeState("waiting", conf.lang.nameCapt);
				}else
					changeState("processing", conf.lang.processing + ret.file.name);
			}
		};
		setMsg();

		

		//处理文件输入
		var handleFile = function(file) {
			if(acceptList.length > 0 && !acceptList.includes("." + file.name.split(".").pop().toLowerCase())) {
                console.log(acceptList);
				setMsg("error", conf.lang.refuseType);
				return;
			}
			ret.file = file;
			setMsg();

			cbfn(file, {
				error: function (msg) {
					if(ret.state == "processing" && ret.file == file) {
						ret.file = null;
						setMsg("error", msg ? (conf.lang.error[1] + msg) : conf.lang.error[0]);
					}
				},
				ok: function () {
					if(ret.state == "processing" && ret.file == file) {
						ret.trueFile = file;
						ret.file = null;
						setMsg("done", conf.lang.done + file.name);
					}
				}
			});
		}

		//当文件更改
		el.fileinput.on("change", function() {
			var file = el.fileinput.get(0).files[0];
			if(file) handleFile(file);
		});



		//拖放文件
		if(conf.drag) {
			function pe(e) {
				e.stopPropagation();
				e.preventDefault();
			}

            /**
             * 方法来自https://www.jianshu.com/p/f96b754032a1
             * 由于会先触发dragenter后dragleave，因此记录最后进入的元素。如果退出的元素是最后进入的元素，说明是真正退出了
			 */
            var lastenter = null;
            el.wrapper.on("dragenter", function(e) {
				pe(e);
				fileDrag = true;
                lastenter = e.target;
				let dt = e.originalEvent.dataTransfer;
				if(!dt.types.includes("Files")) 
                    changeState("error", conf.lang.nonfile, false);
				else 
                    changeState("waiting", conf.lang.drag, false);
			}).on("dragover", function(e) {
				pe(e);
			}).on("dragleave", function(e) {
				pe(e);
                if(e.target == lastenter) {
			    	fileDrag = false;
			    	setMsg();
                }
			}).on("drop", function(e) {
				pe(e);
				fileDrag = false;
				let dt = e.originalEvent.dataTransfer;
                if(dt.types.includes("Files"))
				    handleFile(dt.files[0]);
                else
                    setMsg();
			})
		}


		this.addClass("fileinput").attr("fileinput", "fileinput");
		this.append(el.wrapper);

		return ret;
	}

	//加入jQuery
	$.fn.fileinput = fileinput;
})(jQuery));